package com.hdu.dwh.controller;

import com.hdu.dwh.dao.PaimonBaseDao;
import com.hdu.dwh.pojos.source_access_pojos.MinioConf;
import com.hdu.dwh.properties.MinioProperties;
import com.hdu.dwh.results.ResponseResult;
import com.hdu.dwh.service.MinioService;
import com.hdu.dwh.utils.MinioUtil;
import com.hdu.dwh.utils.OperatorUtil;
import com.hdu.dwh.vos.MinioTreeNodeVo;
import io.minio.ObjectWriteResponse;
import io.minio.Result;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;


@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/minio")
public class MinioController {
    private final MinioUtil minioUtil;
    private final MinioProperties minioProperties;

    @Autowired
    private PaimonBaseDao paimonBaseDao;

    @Autowired
    private MinioService minioService;

    /**
     * 文件上传
     * @param file
     * @return
     */
    @Operation(summary = "文件上传", deprecated = true)
    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(
            @RequestParam("file") MultipartFile file,
            @RequestParam("customName") String customName) {  // 改为必填参数
        try {
            // 验证文件名非空
            if (!StringUtils.hasText(customName)) {
                return ResponseEntity.badRequest().body("自定义文件名不能为空");
            }

            // 保留原始文件扩展名
            String extension = FilenameUtils.getExtension(file.getOriginalFilename());
            String objectName = customName + (StringUtils.hasText(extension) ? "." + extension : "");

            // 安全处理：移除特殊字符
            objectName = objectName.replaceAll("[^a-zA-Z0-9._-]", "_");

            log.info("上传文件: 原始名={}, 自定义名={}", file.getOriginalFilename(), objectName);

            // 执行上传
            ObjectWriteResponse response = minioUtil.uploadFile(
                    minioProperties.getBucketName(),
                    file,
                    objectName,
                    file.getContentType());

            return ResponseEntity.ok("文件上传成功，存储名称: " + objectName);
        } catch (Exception e) {
            log.error("文件上传失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("文件上传失败: " + e.getMessage());
        }
    }
    /**
     * 删除
     *
     * @param fileName
     */
    @Operation(summary = "删除文件", deprecated = true)
    @DeleteMapping("/")
    public void delete(@RequestParam("fileName") String fileName) {
        minioUtil.removeFile(minioProperties.getBucketName(), fileName);
    }

    /**
     * 获取文件信息
     *
     * @param fileName
     * @return
     */
    @Operation(summary = "获取文件信息", deprecated = true)
    @GetMapping("/info")
    public String getFileStatusInfo(@RequestParam("fileName") String fileName) {
        return minioUtil.getFileStatusInfo(minioProperties.getBucketName(), fileName);
    }

    /**
     * 获取文件外链
     *
     * @param fileName
     * @return
     */
    @Operation(summary = "获取文件外链", deprecated = true)
    @GetMapping("/url")
    public String getPresignedObjectUrl(@RequestParam("fileName") String fileName) {
        return minioUtil.getPresignedObjectUrl(minioProperties.getBucketName(), fileName);
    }

    /**
     * 文件下载
     *
     * @param fileName
     * @param response
     */
    @Operation(summary = "文件下载", deprecated = true)
    @GetMapping("/download")
//    @ApiOperation("下载文件")
    public void download(@RequestParam("fileName") String fileName, HttpServletResponse response) {
        try {
            // 从 MinIO 获取指定的对象（文件）的输入流
            InputStream fileInputStream = minioUtil.getObject(minioProperties.getBucketName(), fileName);
            // 设置响应头，指明这是一个附件下载，并指定下载文件的名称
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            // 设置响应的内容类型为强制下载
            response.setContentType("application/force-download");
            // 设置响应的字符编码为 UTF-8
            response.setCharacterEncoding("UTF-8");
            // 将输入流中的文件内容复制到响应输出流中
            IOUtils.copy(fileInputStream, response.getOutputStream());
            response.flushBuffer(); // 刷新响应输出流
        } catch (Exception e) {
            log.error("下载失败");
            System.out.println(e);
        }
    }

    /**
     * 获取MinIO文件目录结构
     * @param bucketName 存储桶名称，如果为空则使用默认存储桶
     * @return MinIO文件目录结构树
     */
    @Operation(summary = "获取MinIO文件目录结构树", deprecated = true)
    @GetMapping("/minioStructure")
    public ResponseResult<List<MinioTreeNodeVo>> getMinioStructure(
            @RequestParam(required = false) String bucketName) {

        try {
            // 如果没有提供bucketName，则使用默认的bucketName
            if (bucketName == null || bucketName.isEmpty()) {
                bucketName = "radar"; // 默认bucket名称，根据配置文件调整
            }

            // 检查bucket是否存在
            if (!paimonBaseDao.getMinioUtil().bucketExists(bucketName)) {
                return ResponseResult.fail("存储桶 " + bucketName + " 不存在");
            }

            // 获取文件列表（递归获取所有文件）
            Iterable<Result<Item>> objectsIterable = paimonBaseDao.getMinioUtil().listObjects(
                    bucketName, "", true);

            // 构建树状结构
            List<MinioTreeNodeVo> tree = buildTreeStructure(objectsIterable);

            return ResponseResult.success("获取文件目录结构成功", tree);
        } catch (Exception e) {
            log.error("获取MinIO文件目录结构失败", e);
            return ResponseResult.fail("获取文件目录结构失败: " + e.getMessage());
        }
    }

    /**
     * 构建树状结构
     * @param objectsIterable MinIO对象列表
     * @return 树状结构
     */
    private List<MinioTreeNodeVo> buildTreeStructure(Iterable<Result<Item>> objectsIterable) throws Exception {
        // 根节点列表
        List<MinioTreeNodeVo> rootNodes = new ArrayList<>();
        // 用于存储所有路径节点的映射
        Map<String, MinioTreeNodeVo> nodeMap = new HashMap<>();

        // 遍历所有对象
        for (Result<Item> result : objectsIterable) {
            Item item = result.get();
            String objectName = item.objectName();

            // 按照 '/' 分割路径
            String[] pathParts = objectName.split("/");

            // 逐级构建路径节点
            StringBuilder currentPath = new StringBuilder();
            for (int i = 0; i < pathParts.length; i++) {
                if (i > 0) {
                    currentPath.append("/");
                }
                currentPath.append(pathParts[i]);

                String path = currentPath.toString();
                // 如果节点不存在，则创建节点
                if (!nodeMap.containsKey(path)) {
                    boolean isDir = (i < pathParts.length - 1) || item.isDir(); // 除了最后一个节点，其他都是目录
                    MinioTreeNodeVo node = new MinioTreeNodeVo(pathParts[i], isDir);
                    nodeMap.put(path, node);

                    // 如果是根级节点，添加到根节点列表
                    if (i == 0) {
                        rootNodes.add(node);
                    }
                }
            }
        }

        // 构建父子关系
        for (Map.Entry<String, MinioTreeNodeVo> entry : nodeMap.entrySet()) {
            String path = entry.getKey();
            MinioTreeNodeVo node = entry.getValue();

            // 查找父节点
            int lastSlashIndex = path.lastIndexOf("/");
            if (lastSlashIndex > 0) {
                String parentPath = path.substring(0, lastSlashIndex);
                MinioTreeNodeVo parentNode = nodeMap.get(parentPath);
                if (parentNode != null) {
                    if (parentNode.getChildren() == null) {
                        parentNode.setChildren(new ArrayList<>());
                    }
                    parentNode.getChildren().add(node);
                }
            }
        }

        return rootNodes;
    }

    @Operation(summary = "获取所有Minio配置")
    @GetMapping("minioConf")
    public ResponseResult<List<MinioConf>> getAllMinioConfs() {
        return ResponseResult.success(minioService.list());
    }

    @Operation(summary = "添加Minio配置")
    @PostMapping("minioConf")
    public ResponseResult<MinioConf> addMinioConf(@RequestBody MinioConf minioConf) {
        minioConf.setCreatedBy(OperatorUtil.getCurrentOperator());
        minioService.save(minioConf);
        return ResponseResult.success(minioConf);
    }

    @Operation(summary = "更新Minio配置")
    @PutMapping("minioConf/{id}")
    public ResponseResult<MinioConf> updateMinioConf(@PathVariable Long id, @RequestBody MinioConf minioConf) {
        MinioConf existingConf = minioService.getById(id);
        if (existingConf == null) {
            return ResponseResult.fail("Minio配置不存在");
        }
        minioConf.setId(id);
        minioService.updateById(minioConf);
        return ResponseResult.success(minioConf);
    }

    @Operation(summary = "删除Minio配置")
    @DeleteMapping("minioConf/{id}")
    public ResponseResult<?> deleteMinioConf(@PathVariable Long id) {
        MinioConf existingConf = minioService.getById(id);
        if (existingConf == null) {
            return ResponseResult.fail("Minio配置不存在");
        }
        minioService.removeById(id);
        return ResponseResult.success("Minio配置删除成功");
    }
    
    @Operation(summary = "根据id获取Minio配置")
    @GetMapping("minioConf/{id}")
    public ResponseResult<MinioConf> getMinioConfById(@PathVariable Long id) {
        MinioConf existingConf = minioService.getById(id);
        if (existingConf == null) {
            return ResponseResult.fail("Minio配置不存在");
        }
        return ResponseResult.success(existingConf);
    }

    @Operation(summary = "根据id获取目录结构树")
    @GetMapping("/minioStructure/{id}/{bucket}")
    public ResponseResult<List<MinioTreeNodeVo>> getMinioStructureById(
            @PathVariable Long id, @PathVariable String bucket) throws Exception {
        if (bucket == null || bucket.isEmpty()) {
            throw new IllegalArgumentException("Bucket名称不能为空");
        }
        return ResponseResult.success(minioService.getFileTreeById(id, bucket));
    }

    @Operation(summary = "获取Minio的所有存储桶")
    @GetMapping("/buckets/{id}")
    public ResponseResult<List<String>> getAllBuckets(@PathVariable Long id) throws Exception {
        List<String> buckets = minioService.getAllBuckets(id);
        return ResponseResult.success(buckets);
    }
    
}
